package com.grj.parking.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * 多级缓存配置类：本地缓存(Caffeine) + 分布式缓存(Redis)
 */
@Configuration
@EnableCaching
public class CacheConfig {

    // ------------------------------ 本地缓存配置 (Caffeine) ------------------------------

    /**
     * 停车场基础信息本地缓存
     * 特点：数据稳定，访问频繁
     */
    @Bean(name = "allLocalCache")
    public Cache<String, Object> allLocalCache() {
        return Caffeine.newBuilder()
                .maximumSize(500000000)  // 最大缓存数量：50条（适合中小型停车场系统）
                .expireAfterWrite(30, TimeUnit.DAYS)  // 写入后30分钟过期
                .build();
    }

    @Bean
    public Cache<String, String> messageCache() {
        return Caffeine.newBuilder()
                .maximumSize(100000000)                    // 最大缓存1000条消息
                .expireAfterWrite(10, TimeUnit.DAYS) // 写入10分钟后过期
                .recordStats()                        // 记录缓存统计信息
                .build();
    }

    // ------------------------------ Redis分布式缓存配置 ------------------------------

    /**
     * RedisTemplate配置（用于手动操作Redis缓存）
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // JSON序列化配置
        Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 解决jackson2无法反序列化LocalDateTime的问题
        objectMapper.findAndRegisterModules();
        jacksonSerializer.setObjectMapper(objectMapper);

        // String序列化
        StringRedisSerializer stringSerializer = new StringRedisSerializer();

        // key采用String序列化方式
        template.setKeySerializer(stringSerializer);
        // hash的key也采用String序列化方式
        template.setHashKeySerializer(stringSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jacksonSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jacksonSerializer);

        template.afterPropertiesSet();
        return template;
    }

    /**
     * Redis缓存管理器（用于@Cacheable注解方式）
     */
    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
        // 默认配置
        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(10))  // 默认过期时间10分钟
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(new Jackson2JsonRedisSerializer<>(Object.class)))
                .disableCachingNullValues();  // 不缓存null值

        // 针对不同缓存设置差异化过期时间
        return RedisCacheManager.builder(factory)
                .cacheDefaults(defaultConfig)
                .withCacheConfiguration("vehicleLocalCache",  // 车辆缓存
                        defaultConfig.entryTtl(Duration.ofMinutes(5)))  // 5分钟过期
                .withCacheConfiguration("gateLocalCache",  // 闸口缓存
                        defaultConfig.entryTtl(Duration.ofHours(1)))  // 1小时过期
                .withCacheConfiguration("parkingLotLocalCache",  // 停车场缓存
                        defaultConfig.entryTtl(Duration.ofHours(2)))  // 2小时过期
                .withCacheConfiguration("allLocalCache",  // 停车场缓存
                        defaultConfig.entryTtl(Duration.ofHours(2)))  // 2小时过期
                .build();
    }
}
